<!doctype html>
<html lang="zh-cn">
<head>

    <meta charset="utf-8">
    <meta name="generator" content="Hugo 0.57.2" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>桥接模式 | The Sky of OtsWang</title>
    <meta property="og:title" content="桥接模式 - The Sky of OtsWang">
    <meta property="og:type" content="article">
        
    <meta property="article:published_time" content="2018-12-28T14:22:32&#43;08:00">
        
        
    <meta property="article:modified_time" content="2018-12-28T14:22:32&#43;08:00">
        
    <meta name="Keywords" content="[桥接模式]">
    <meta name="description" content="桥接模式">
        
    <meta name="author" content="OtsWang">
    <meta property="og:url" content="https://otswang.gitee.io/hugo/post/design/bridge/">
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">

    <link rel="stylesheet" href="/hugo/css/normalize.css">
    
        <link rel="stylesheet" href="/hugo/css/prism.css">
    
    <link rel="stylesheet" href="/hugo/css/style.css">
    <script type="text/javascript" src="//cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>

    


    
    
</head>

<body>
<header id="header" class="clearfix">
    <div class="container">
        <div class="col-group">
            <div class="site-name ">
                
                    <a id="logo" href="https://otswang.gitee.io/hugo/">
                        The Sky of OtsWang
                    </a>
                
                <p class="description">擅长写HelloWorld的小小码农</p>
            </div>
            <div>
                <nav id="nav-menu" class="clearfix">
                    
                    
                    <a  href="https://otswang.gitee.io/hugo/" title="Home">Home</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/tags/" title="Tags">Tags</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/categories/" title="Categories">Categories</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/archives/" title="Archives">Archives</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/about/" title="About">About</a>
                    
                </nav>
            </div>
        </div>
    </div>
</header>


<div id="body">
    <div class="container">
        <div class="col-group">

            <div class="col-8" id="main">
                <div class="res-cons">
                    <article class="post">
                        <header>
                            <h1 class="post-title">桥接模式</h1>
                        </header>
                        <date class="post-meta meta-date">
                            2018年12月28日
                        </date>
                        
                        <div class="post-meta">
                            <span>|</span>
                            
                                <span class="meta-category"><a href="https://otswang.gitee.io/hugo/categories/design">Design</a></span>
                            
                        </div>
                        
                        
                        
                        <div class="post-content">
                            <p>桥接模式(Bridge Pattern)：将抽象部分与它的实现部分分离，使它们都可以独立地变化。它是一种对象结构型模式，又称为柄体(Handle and Body)模式或接口(Interface)模式。</p>

<h2 id="问题引入">问题引入</h2>

<p>画笔有两种：蜡笔和毛笔。 如果需要粗中细三类和12种颜色，则对于蜡笔需要3*12共36个，而对于毛笔，则需要3+12共15个，这是因为毛笔把粗细和颜色分离开来。而当需要增加一种粗细（细plus）时，对于蜡笔需要新增12个，对于毛笔需要新增1个。</p>

<p>编程实例：</p>

<p>跨平台的图像浏览系统：</p>

<p>需要支持windows，linux和unix的图像浏览系统，支持jpg, bmp, png等图像格式。在类设计时，对Image类不断加入新的类继承，最终实现如上的跨平台图像浏览系统。</p>

<h2 id="桥接模式介绍">桥接模式介绍</h2>

<p><strong>在桥接模式结构图中包含如下几个角色：</strong></p>

<ul>
<li><p>Abstraction（抽象类）：用于定义抽象类的接口，它一般是抽象类而不是接口，其中定义了一个Implementor（实现类接口）类型的对象并可以维护该对象，它与Implementor之间具有关联关系，它既可以包含抽象业务方法，也可以包含具体业务方法。</p></li>

<li><p>RefinedAbstraction（扩充抽象类）：扩充由Abstraction定义的接口，通常情况下它不再是抽象类而是具体类，它实现了在Abstraction中声明的抽象业务方法，在RefinedAbstraction中可以调用在Implementor中定义的业务方法。</p></li>

<li><p>Implementor（实现类接口）：定义实现类的接口，这个接口不一定要与Abstraction的接口完全一致，事实上这两个接口可以完全不同，一般而言，Implementor接口仅提供基本操作，而Abstraction定义的接口可能会做更多更复杂的操作。Implementor接口对这些基本操作进行了声明，而具体实现交给其子类。通过关联关系，在Abstraction中不仅拥有自己的方法，还可以调用到Implementor中定义的方法，使用关联关系来替代继承关系。</p></li>

<li><p>ConcreteImplementor（具体实现类）：具体实现Implementor接口，在不同的ConcreteImplementor中提供基本操作的不同实现，在程序运行时，ConcreteImplementor对象将替换其父类对象，提供给抽象类具体的业务操作方法。</p></li>
</ul>

<p>在使用桥接模式时，需要先识别出一个类具有两个独立变化的维度，将他们设计成两个独立的继承等级结构，为两个维度都提供抽象层，并建立抽象耦合。</p>

<p><a href="https://www.draw.io/?lightbox=1&amp;highlight=0000ff&amp;edit=_blank&amp;layers=1&amp;nav=1&amp;title=%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.xml#R7V1bj5s4FP41ltqHGWHuPOY23ZVatdvp7rZPFRM8CVuCI8I0mf76tQNOCDYJydgBdSyNVDDGAX%2Fn8p3jYwqs0WLzLguX8w84QgkwjWgDrDEwTQgNl%2FxDW56LFtcJioZZFkdlp33DffwLlY1G2foUR2h10DHHOMnj5WHjFKcpmuYHbWGW4fVht0ecHP7qMpwhruF%2BGiZ8679xlM%2FZe7nB%2FsIfKJ7Ny5%2F2Ta%2B4sAhZ5%2FJNVvMwwutKkzUB1ijDOC%2BOFpsRSujksXkp7rtruLp7sAyleZsbPr4z4u%2FhXx%2B%2F%2F4Mm8Nto%2FJ%2BxcW48vxjmZ5g8lW9cPm3%2BzKYgw09phOgoBrCG63mco%2FtlOKVX1wR00jbPFwk5g%2BSwHA5lOdo0PijcvT6RG4QXKM%2BeSZfyBicop7AUGd8vZ3C9B8BmszqvzL3llo1hCfpsN%2FZ%2BXshBOTXnTJPXv2kKnNOz5DvXnCXITdLgYZVn4TSPccrN12odL5IwJWfDR5zm9%2BUVi5yHSTxLyfGUTAXKSAOdqJgo5aC8kGM6n9N5nETvw2f8RF9tlYfTH%2BxsOMdZ%2FIsMG7IZJ5ezvLQvpnvQ457eWeKWoRXp84mhAGtNH8LNQcf34SovG6Y4ScLlKn7Yvga9cRFmszgd4jzHi7KTBNxtZhpL4HcGpgI8dAXq4buKcDcFyjGkxjZG1NoOqM1%2BXiJOAsgc5FtkMvwDjXCCCdTjFBciESdJrYlJRYIe80aZWBGVi9PZ%2B22fsb1v%2BVxOBG3C5N7HZGuM53EUoZTiifMwDwvwKFJLHKf5dqacIfkj8zkybh3gkAcfkXO4Pyd%2FtHuWj3BKxT3e4oiIZKwRlY4D8TZbSUCzevFiwcTAbScFpiopsE6byCTeAlkAztwpvAjtBcEtQXt4v1D0xzeQEwGLFwFLAHcSPqDkE17FW1tljbOib00MTiGtClzHbKniirC1hRo%2BMsHAwEuUhYWBN9681TquUsfdlpZemY47nBz8uVgmaEFeiqDY0sND7eGPe3jPrHl46Hfs4V3t4RXZfaffTr1F3KOd%2BoXgdu3URaE%2FVeqdR6e2%2FXV7dVXQd%2B7Ig9N6jdJoQBNo5CyKwwVOoy%2FzmM43uXAX05%2FbzjY5Yz7XPsxxkAnKnr9WT77Re8jUk9NNnH9lI5Dj%2FZXiOVDEpeVq3pM8K37Kpui01yK0YIaOYWWKsRKBk6GEqMbPw2cToVMO94nKYiW15R569l0sz4Yo3qm8q5rMqw1UpwjcQMVLcwNthWX3ji9I9RicAH1Gj8QTRBekfDQhPDPlY0O7Y0II%2BVyfZoSSMgGGWBb6QgmhKN2nOaEkeLsmhVCUxjtghZoRKgG%2Bc0oI%2BSTfZJMTerc6Rg0fEkwdaYUGQpfjiFVSyIjfjgZ%2BO%2FCTUogfc5cnmZ99NeZXd%2BGOeSHzc7wTA6lmfnzoQHRlmqEwR8k%2BGTjQ5E8S%2BXOtBqrf3Xpfi6yQwERE4Wq%2BXR%2BHR4JIwi7EQaRxa9vVOBLeGpbPGj6hLCbvRmWnrS05KtwnDYd%2FNcPhX2gnTLudXSAohc%2BVbqWvPPk8pTTeuMbRx4Cueaw%2FOSgeQKqNMvnoVEcnklhMcJTFdB6dmKLAVEcnkuDtOjphYOqcdQfgdx6hmHxsKqKeQ009JVFP3%2B4b9bREnl099XQcq8Y9Denck0m35p6yuOeNBTvgnuJaKc09X%2B6fCg3pMffky6M095QGb%2Bfcs6kISnNP9eB3zj0tPq4cJTEq%2FZkmmy8nm%2FUMeVvI1XHNpmBTe%2FKXarvV970MejODQni79uRWE0Unw89x9IYq9Vut3%2BoEoHtvzjP1v1c80JVMAiF5KZ8tOMgriFe5DRfs17nhreF55fkFeYO2699MwE%2BmEhpg0uvfR%2BaWX%2FxUIjoQ1Ctjq%2FmoajZKtvCYLYWnocT5dxSe8xNVh78TBDVRVJB4sgT1%2FBMXDO5AMAQTDwxGILA5OdXRymXRSj0XGVgtfRo0aiInz6mJivqtYpfmdEtJNJE5m8g0JNv7EqiwRLsOVFTA23WgYjdV2a9QXgBXZBuJdFmwMGz0apSFa%2F6K1n25wtE2iKmvhcmTDkF%2BauKAgQ0GHj3w78DQ0xRAGQXYof3MPHsgEAl4zZSlLcpbVWyANgeXm4NC3c6iAiLs1VEBUVZLUwFJ8IqogFC1VaErWluuOXut0nIxF3n466q0YMl5YoOhDwZj7eHVe3jL6J2Hd1rUmLxgexY4nUc8Kqmnd1xdL%2BVc%2F85h6%2Bq1K2eUbdF2Gk3a5Fh4t%2BekrcX3VzVpuxTezkmbKCOrSZtSzDsnbY4gJUu4GpktQtc0aVNfR2b1j7SJSkflkbbKwrBn7%2FYlsHoDIHmfApPv10T1zl3%2FrWUG2baV5o0KR%2FurWS92RIsLmnbK%2Bfrb%2Bd%2Fwua6PEiwdaNopC96uaafT9A0fTTuVYd497WyR%2Flfy3Z4K%2BzC5bZLOrlJNYbkjWwjtEyOBQZ2FehdyFMs5NZIk0mJCp%2FZDJ%2FZXWmb9ya6xwdIR1bkFYGCCYAQmPvADMORFX0dTl0VTXo2a9qDOjf2aJi%2BXOTI5JW1suVk%2BvOKip20ZI2n%2BTFwU0VJd3qRYDryWem4pU3M%2BRslQpA27rM%2FKwbrz7jxN5urqJWXaXmhTfzMSrq5eUghv1xkJt6l66cCba6WWi3rnOQmXX%2FeYZQjp%2FxhAWnTG5Qa6d%2BKXfRxWdYGS27ZAyf19Vq1kZVxcUZGK5mVyTHjPC5TY%2F3OteZkKeLvmZZ4olaZ5mWLUO%2BdlHp9ie6BHmpbJoWW%2B3zta5vHZNJm07LolSEx%2BXxOZ%2Bx1LkDyd8FPmg7zzP7F2XR%2BkE34K4e2cWOqEXweod08sFRc697gIiS1X9oqT2HUeemkRUv2DVsqKkFz3zCIkz6s%2F2TWKkDxBWmTiAn8AhmNahETswQDSsiTfAgN%2Fu%2B3DB4zc8yavIuPnWr%2FGAGzn8dbzOEf3xOrR31xn4XJr3Z6IHY6AtJAH1uuEDN4WeSJTpKp8wBekNujXUSYgmNBNN%2F6Ebsl5RQjVF%2Fx9QUwqCSFymmGcV1WOvNT8A44Q7fE%2F">UML图</a></p>

<p>从桥接模式分析画笔：</p>

<p>对于毛笔而言,由于型号是其固有的维度,因此可以设计成一个抽象的毛笔类,在该类中声明并实现毛笔的业务方法,而将各种型号的毛笔作为其子类;颜色是毛笔的另一个维度,由于他与毛笔之间存在一种设置的关系,因此提供一个抽象的颜色接口,而将具体的颜色作为实现该接口的子类,在此可以认为:<strong>型号是毛笔的抽象部分,而颜色是毛笔的实现部分</strong>.</p>

<p><strong>一般流程</strong></p>

<p>实现部分的接口:</p>

<pre><code class="language-java">interface Implementor {
    public void operationImpl ();
}
</code></pre>

<p>在实现了Implementor接口的子类中实现了该接口中声明的方法,用于定义与该维度相对应的一些具体方法.</p>

<p>抽象部分:</p>

<pre><code class="language-java">abstract class Abstraction {
    protected Implementor impl;     // 定义实现类接口对象

    public void setImpl (Implemetor impl) {
        this.impl = impl;
    }

    public abstract void operation ();  // 声明抽象业务方法
}

</code></pre>

<p>在抽象类Abstraction中定义了一个实现类接口类型的成员变量 impl, 再通过<strong>注入</strong>的方式进行赋值, protected是为了在子类中使用.</p>

<p>抽象类的子类一般称为扩充抽象类(RefinedAbstraction), 典型的类实现如下:</p>

<pre><code class="language-java">class RefinedAbstraction extends Abstraction {
    public void operaion () {
        // 业务代码
        impl.operationImpl();
        // 业务代码
    }
}
</code></pre>

<h2 id="桥接模式总结">桥接模式总结</h2>

<p>桥接模式是设计Java虚拟机和实现JDBC等驱动程序的核心模式之一，应用较为广泛。在软件开发中如果一个类或一个系统有多个变化维度时，都可以尝试使用桥接模式对其进行设计。桥接模式为多维度变化的系统提供了一套完整的解决方案，并且降低了系统的复杂度。</p>

<p><strong>桥接模式的主要优点如下：</strong></p>

<p>(1)分离抽象接口及其实现部分。桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系，使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自维度的变化，也就是说抽象和实现不再在同一个继承层次结构中，而是“子类化”它们，使它们各自都具有自己的子类，以便任何组合子类，从而获得多维度组合对象。</p>

<p>(2)在很多情况下，桥接模式可以取代多层继承方案，多层继承方案违背了“单一职责原则”，复用性较差，且类的个数非常多，桥接模式是比多层继承方案更好的解决方法，它极大减少了子类的个数。</p>

<p>(3)桥接模式提高了系统的可扩展性，在两个变化维度中任意扩展一个维度，都不需要修改原有系统，符合“开闭原则”。</p>

<p><strong>桥接模式的主要缺点如下：</strong></p>

<p>(1)桥接模式的使用会增加系统的理解与设计难度，由于关联关系建立在抽象层，要求开发者一开始就针对抽象层进行设计与编程。</p>

<p>(2)桥接模式要求正确识别出系统中两个独立变化的维度，因此其使用范围具有一定的局限性，如何正确识别两个独立维度也需要一定的经验积累。</p>

<p><strong>在以下情况下可以考虑使用桥接模式：</strong></p>

<p>(1)如果一个系统需要在抽象化和具体化之间增加更多的灵活性，避免在两个层次之间建立静态的继承关系，通过桥接模式可以使它们在抽象层建立一个关联关系。</p>

<p>(2)“抽象部分”和“实现部分”可以以继承的方式独立扩展而互不影响，在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合，即系统需要对抽象化角色和实现化角色进行动态耦合。</p>

<p>(3)一个类存在两个（或多个）独立变化的维度，且这两个（或多个）维度都需要独立进行扩展。</p>

<p>(4)对于那些不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统，桥接模式尤为适用。</p>

<h2 id="另一个例子">另一个例子</h2>

<pre><code class="language-java">public class BridgePattern {
    public static void main(String[] args){
        Shape[] shapes = new Shape[] {
                new CircleShape(1,2,3,new DrawingAPIImpl1()),
                new CircleShape(2,3,4,new DrawingAPIiml2())
        };

        System.out.println(&quot;origin&quot;);
        for (Shape shape : shapes){
            shape.draw();
        }

        System.out.println(&quot;resize&quot;);
        for (Shape shape : shapes){
            shape.resizeByPercentage(2.5);
            shape.draw();
        }
    }
}


/**
 * Implementor
 */
interface DrawingAPI {
    void drawCircle(double x, double y, double radius);
}

/**
 * 一个实现
 */
class DrawingAPIImpl1 implements DrawingAPI {
    @Override
    public void drawCircle(double x, double y, double radius) {
        System.out.printf(&quot;api 1 . circle at %f:%f radius %f\n&quot;, x, y, radius);
    }
}

class DrawingAPIiml2 implements DrawingAPI {
    @Override
    public void drawCircle(double x, double y, double radius) {
        System.out.printf(&quot;api 2 . circle at %f:%f radius %f\n&quot;, x, y, radius);
    }
}


/**
 * Abstraction
 */
abstract class Shape {
    protected DrawingAPI drawingAPI;

    public void setDrawingAPI(DrawingAPI drawingAPI) {
        this.drawingAPI = drawingAPI;
    }

    public abstract void draw(); // low level
    public abstract void resizeByPercentage(double pct);  // high level
}

class CircleShape extends Shape {
    private double x, y, radius;

    public CircleShape(double x, double y, double radius, DrawingAPI drawingAPI) {
        super.setDrawingAPI(drawingAPI);
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    @Override
    public void draw() {
        drawingAPI.drawCircle(x, y, radius);
    }

    @Override
    public void resizeByPercentage(double pct) {
        radius *= pct;
    }
}

</code></pre>
                        </div>

                        


                        

<div class="post-archive">
    <h2>See Also</h2>
    <ul class="listing">
        
        <li><a href="/hugo/post/design/prototype/">原型模式</a></li>
        
        <li><a href="/hugo/post/design/factory/">工厂方法模式</a></li>
        
        <li><a href="/hugo/post/design/single/">单例模式</a></li>
        
    </ul>
</div>


                        <div class="post-meta meta-tags">
                            
                            <ul class="clearfix">
                                
                                <li><a href="https://otswang.gitee.io/hugo/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F">设计模式</a></li>
                                
                            </ul>
                            
                        </div>
                    </article>
                    
    

    
    
                </div>
            </div>
            <div id="secondary">

    <section class="widget">
        <form id="search" action="//www.google.com/search" method="get" accept-charset="utf-8" target="_blank" _lpchecked="1">
      
      <input type="text" name="q" maxlength="20" placeholder="Search">
      <input type="hidden" name="sitesearch" value="https://otswang.gitee.io/hugo/">
      <button type="submit" class="submit icon-search"></button>
</form>
    </section>

    
    <div class="clear">
        <div class="toc-article">
            <div class="toc-title">文章目录</dixsv>
            <nav id="TableOfContents">
<ul>
<li>
<ul>
<li><a href="#问题引入">问题引入</a></li>
<li><a href="#桥接模式介绍">桥接模式介绍</a></li>
<li><a href="#桥接模式总结">桥接模式总结</a></li>
<li><a href="#另一个例子">另一个例子</a></li>
</ul></li>
</ul>
</nav>
        </div>
    </div>
    

</div>
        </div>
    </div>
</div>
<footer id="footer">
    <div class="container">
        &copy; 2020 <a href="https://otswang.gitee.io/hugo/">The Sky of OtsWang By OtsWang</a>.
        Powered by <a rel="nofollow noreferer noopener" href="https://gohugo.io" target="_blank">Hugo</a>.
        <a href="https://www.flysnow.org/" target="_blank">Theme</a> based on <a href="https://github.com/Dudiao137/maupassant-hugo" target="_blank">maupassant-ots</a>.
        
    </div>
</footer>


    <script type="text/javascript">
    
    (function(){
        $("pre code").parent().addClass("line-numbers")
    }())

    window.MathJax = {
        tex2jax: {
            inlineMath: [ ['$','$'] ],
            processEscapes: true
        }
    };
    </script>
    <script type="text/javascript" src="/hugo/js/prism.js" async="true"></script>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML' async></script>

<a id="rocket" href="#top"></a>
<script type="text/javascript" src="/hugo/js/totop.js?v=0.0.0" async=""></script>







 
 <script src="https://mermaidjs.github.io/scripts/mermaid.min.js"></script>
 <script>
       mermaid.initialize({ startOnLoad: true });
 </script>
</body>
</html>
